/**
  ******************************************************************************
  * @file    can.c
  * @author  Qilong Huang
  * @version V0.0.1
  * @date    09-03-2020
  * @brief    This file contains CAN specific functions.
  *          
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; KION(SZ) R&D Center
  *
  * Licensed under KION, (the "License");
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "CAN.h"

/* Local variables ------------------------------------------------------------------*/

static s16 inhibit_restart_bus_CAN = 0;     // Inhibit auto-restart CAN bus after bus-off

/* Global variables ------------------------------------------------------------------*/
u16 can_node_id = 4;
s16 can_baud_rate = CAN_500KBAUD;
s16 can_bus_on = 0;                 // CAN Bus Status (0=off, non-0=on)
s16 can_error_status = 0;           // Error Status: Bit0=EWRN, Bit1=BOFF
s16 working_can_slave_id = CAN_SLAVE_ID_DEF;
s16 working_can_master_id = CAN_MASTER_ID_DEF;

CanRxMsg CANopenRxMsgBuf[CANOPEN_RX_MSG_BUF] = {0};
u8 CANopen_rx_buf_head;
u8 CANopen_rx_buf_tail;

CanRxMsg CANRxMsgBuf[CAN_RX_MSG_BUF] = {0};
u8 CAN_rx_buf_head;
u8 CAN_rx_buf_tail;

u16 flashing_timeout = 0;
s16 can_timestamp_timeout = 0;
s16 can_heartbeat_timeout = 0;
s16 can_test_timeout = 0;
/**
  * @brief  Configures the NVIC for CAN.
  * @param  None
  * @retval None
  */
void CANopen_NVIC_Config(void)
{
    NVIC_InitTypeDef  NVIC_InitStructure;

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

    NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}
/**
* @brief    Configure CAN. Use CAN1
* @param    none
* @note     none
* @retval   none
*/
void CAN_Config(void)
{
    u8 i = 0;
    u8 filter_number = 0;

    GPIO_InitTypeDef GPIO_InitStructure = {0};
    CAN_FilterInitTypeDef CAN_FilterInitStructure = {0};
    CAN_InitTypeDef CAN_InitStructure = {0};

    if(can_bus_on)
    {
//        CAN_Enabled = 0;                                                                                          // ----  Be modify
        can_bus_on = 0;
    }

    /* Configure CAN pin: RX */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_CANOPEN_RX;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIO_CANOPEN, &GPIO_InitStructure);

    /* Configure CAN pin: TX */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_CANOPEN_TX;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIO_CANOPEN, &GPIO_InitStructure);

    /* CAN register init */
    CAN_DeInit(CANOPEN_CAN);
    CAN_StructInit(&CAN_InitStructure);

    /* CAN cell init */
    CAN_InitStructure.CAN_TTCM = DISABLE;
    CAN_InitStructure.CAN_ABOM = ENABLE;
    CAN_InitStructure.CAN_AWUM = DISABLE;
    CAN_InitStructure.CAN_NART = DISABLE;
    CAN_InitStructure.CAN_RFLM = DISABLE;
    CAN_InitStructure.CAN_TXFP = DISABLE;
    CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;

    CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
    CAN_InitStructure.CAN_BS1 = CAN_BS1_9tq;
    CAN_InitStructure.CAN_BS2 = CAN_BS2_8tq;
	CAN_InitStructure.CAN_Prescaler = 4;

    CAN_Init(CAN1, &CAN_InitStructure);
    //CAN_Set_Baudrate(can_baud_rate);

    for(i = filter_number; i < FILTER_NUMBER_DEF; i++)
    {
        /* CAN filter init */
        CAN_FilterInitStructure.CAN_FilterNumber = i;
        CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
        CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
        CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
        CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
        CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
        CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
        CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;
        CAN_FilterInitStructure.CAN_FilterActivation = DISABLE;
        CAN_FilterInit(&CAN_FilterInitStructure);
    }
    
    working_can_master_id = (can_node_id >> 5) & 0x03;
    working_can_slave_id = can_node_id  & 0x1f;
    canopen_init();                                                                    


    CANopen_NVIC_Config();

    /* Enable FIFO 1 message pending Interrupt */
    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
//    CAN_Enabled = 1;                                                                                         // ----  Be modify
    can_bus_on = 1;
    CAN_rx_buf_head = 0;
    CAN_rx_buf_tail = 0;
}

/**
* @brief    set baud rate.
* @param    rate:can baud rate
* @note     none
* @retval   none
*/
u8 CAN_Set_Baudrate(u8 rate)
{
    u8 InitStatus = CAN_InitStatus_Failed;
    u32 wait_ack = 0x00000000;
    CAN_InitTypeDef  CAN_InitStructure = {0};

    CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
    CAN_InitStructure.CAN_BS1 = CAN_BS1_9tq;
    CAN_InitStructure.CAN_BS2 = CAN_BS2_8tq;


    /*
    BaudRate = 1/NominalBitTime
    NominalBitTime=tq+tbs1+tbs2
    */
    if(rate == CAN_250KBAUD)
    {
        CAN_InitStructure.CAN_Prescaler = 6;
    }
    else if(rate == CAN_500KBAUD)
    {
        CAN_InitStructure.CAN_Prescaler = 4;
    }
    else//125KABUD
    {
        CAN_InitStructure.CAN_Prescaler = 12;
    }
    
    /* Request initialisation */
    CANOPEN_CAN->MCR |= CAN_MCR_INRQ ;

    /* Wait the acknowledge */
    while (((CANOPEN_CAN->MSR & CAN_MSR_INAK) != CAN_MSR_INAK) && (wait_ack != INAK_TIMEOUT))
    {
        wait_ack++;
    }

    /* Check acknowledge */
    if ((CANOPEN_CAN->MSR & CAN_MSR_INAK) != CAN_MSR_INAK)
    {
        InitStatus = CAN_InitStatus_Failed;
    }
    else 
    {
        CANOPEN_CAN->BTR |= ((u32)CAN_InitStructure.CAN_SJW << 24) | ((u32)CAN_InitStructure.CAN_BS1 << 16) |
                     ((u32)CAN_InitStructure.CAN_BS2 << 20) | ((u32)CAN_InitStructure.CAN_Prescaler - 1);   
        /* Request leave initialisation */
        CANOPEN_CAN->MCR &= ~(u32)CAN_MCR_INRQ;
        wait_ack = 0;
        while (((CANOPEN_CAN->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) && (wait_ack != INAK_TIMEOUT))
        {
            wait_ack++;
        }
        if ((CANOPEN_CAN->MSR & CAN_MSR_INAK) == CAN_MSR_INAK)
        {
            InitStatus = CAN_InitStatus_Failed;
        }
        else
        {
            InitStatus = CAN_InitStatus_Success ;
        }
    }
    return InitStatus;
}

/**
* @brief	make cob id.
* @param	type:can message type
* @param	master_id:master id
* @param	slave_id:slave id
* @note     none
* @retval   none
*/
u16 make_cob_id(u16 type, u16 master_id, u16 slave_id)
{
    return( (type << 7) | (master_id << 5) | (slave_id) );
}


/**
* @brief    check can bus is on or off
* @param    none
* @note     none
* @retval   none
*/
static void check_busoff(void)
{
    static s16 busoff_timeout = 0;
    can_error_status = CANOPEN_CAN->ESR >> 4;
    if(CAN_GetFlagStatus(CANOPEN_CAN,CAN_FLAG_EPV))
    {  
        if(busoff_timeout < CANOPEN_FAULT_DELAY)
        {
            busoff_timeout++ ;
        }
        if (inhibit_restart_bus_CAN == 0) 
        {
            CAN_Config();
        }
    }
    else if(CAN_GetLSBTransmitErrorCounter(CANOPEN_CAN) == 0)
    {
        if(busoff_timeout > 0)
        {
            busoff_timeout--;
        }
    }
    if(busoff_timeout >= CANOPEN_FAULT_DELAY)
    {
        Disp_DhsbErrCode[0] = 706;
    }
    else if(busoff_timeout <= 0)
    {
        Disp_DhsbErrCode[0] = 0;
    }
}

/**
* @brief	can task main entry
* @param	none
* @note     none
* @retval   none
*/
void CAN1_task(void const *argument)
{
    U8 i;
    task_status[CAN_ID] = ALIVE;
//	CAN_PDO_Enabled = 1;
    can_nmt_state = CAN_BOOTUP;
    can_send_heartbeat(can_nmt_state);
    can_tx_msg_from_buff(); 
    can_nmt_state = CAN_PRE_OPERATIONAL;
    // Tasks must run in an infinite loop:
    while (TRUE)
    {
        //check_busoff();
        while(CAN_rx_buf_head != CAN_rx_buf_tail)
        {           
            process_msg(&CANRxMsgBuf[CAN_rx_buf_tail]);
            CAN_rx_buf_tail++;
            CAN_rx_buf_tail &= (CAN_RX_MSG_BUF - 1);
        }
        
        kwp_period_transmit();

		can_heartbeat_timeout -= 1;
        if(can_nmt_state == CAN_OPERATIONAL)              //Send Pro-operational 40ms
        {
            can_timestamp_timeout -= 1;
            if(0 >= can_heartbeat_timeout)
            {
                can_heartbeat_timeout = 5;
                can_send_heartbeat_operational();
                can_tx_msg_from_buff(); 
            }         
            if(0 >= can_timestamp_timeout)
            {
                can_timestamp_timeout = 500;
                can_send_timestamp(); 
                can_tx_msg_from_buff(); 
            }                
        }
        else                                                  //Send Pro-operational 40ms
        {
            if(0 >= can_heartbeat_timeout)
            {
                can_heartbeat_timeout = 20;
                can_send_heartbeat(can_nmt_state);
                can_tx_msg_from_buff(); 
            }
        }
        if(Test_step_counter == 26)
        {
            can_test_timeout -= 1;
            if(0 >= can_test_timeout)
            {
                for(i = 0; i < 8; i ++)
                {
                    test_can_transmit_buf[i] += 0x11;
                    if(test_can_transmit_buf[i] >= 0xff)
                    {
                        test_can_transmit_buf[i] = 0x00;
                    }
                }
                can_test_timeout = 500;
                can_send_testtamp(test_can_transmit_buf);
                can_tx_msg_from_buff(); 
            }
        }

        task_status[CAN_ID] = ALIVE;
        osDelay(CAN_ITV);
    }  // end while infinite loop
}  // end CAN1_task()    

